﻿using dz.db.util.core;
using dz.loger.core;
using dz.u9.jky.schema.Common;
using dz.util.core;
using Dz.WorkerService.QueryParm;

namespace Dz.WorkerService
{
    public abstract class BaseTaskItem : IAsyncDisposable
    {
        private PeriodicTimer _timer;
        private readonly SemaphoreSlim _semaphore = new(1, 1); // 关键改进
        private Task? _executionTask;
        private readonly CancellationTokenSource _cts = new();
        protected string docType, table,processId;
        protected string method;
        protected SqlUtils sqlUtils;
        protected DateTime sDate, eDate;
        private TimeSpan timeSpan;

        protected string Name { get; init; }

  
        public BaseTaskItem(string name,TimeSpan interval) 
        {
            sqlUtils = new SqlUtils(Config.Instance.GetConnectionString("U9"));
            Name = name;
            timeSpan = interval;
            Init();
            //Start();
        }

        protected virtual void Init()
        {
            
        }
   

        public async Task<Task> Start()
        {
            DateTime now = DateTime.Now;
            DateTime nextRun = now.Date.AddDays(1);          // 明天的 00:00:00
            int millisToWait = (int)(nextRun - now).TotalMilliseconds;

            await Task.Delay(millisToWait);
            _timer = new PeriodicTimer(timeSpan);
            await Process();

            _executionTask = RunAsync();

            return _executionTask;
        }

        private async Task RunAsync()
        {
            try
            {
                while (await _timer.WaitForNextTickAsync(_cts.Token))
                {
                    // 非阻塞尝试获取锁，若失败则跳过本次执行
                    if (!await _semaphore.WaitAsync(TimeSpan.Zero, _cts.Token))
                    {
                        LogUtil.Instance.Debug($"{Name} 任务正在运行，等待下次触发执行");
                        continue;
                    }

                    try
                    {   
                        await Process();
                        //await ExecuteActionAsync();
                    }
                    finally
                    {
                        _semaphore.Release();
                    }
                }
            }
            catch (OperationCanceledException ex)
            {
                //智能排序

                LogUtil.Instance.Error($"{Name} {ex.Message}");
                LogUtil.Instance.Error($"{Name} {ex.StackTrace}");
            }
        }

        private async Task ExecuteActionAsync()
        {
            try
            {
                List<long> ids = GetProcessIds(); // 获取需要处理的id集合

                LogUtil.Instance.Debug($"{Name} 开始于{DateTime.Now}");
                //await Parallel.ForEachAsync(ids, async (id, cancellationToken) =>
                //{
                //    await Process(id);
                //});

                //OrderablePartitioner<long> partitioner = Partitioner.Create(ids);
                //var options = new ParallelOptions { MaxDegreeOfParallelism = 16 };

                await Parallel.ForEachAsync(
            ids,
            new ParallelOptions { MaxDegreeOfParallelism = 4 },
            async (item, cancellationToken) =>
            {
                await Process(item);
            });



                LogUtil.Instance.Debug($"{Name} 结束于{DateTime.Now}");
            }
            catch (Exception ex)
            {
                LogUtil.Instance.Error(ex);
            }
        }

        protected virtual async Task Process(long param)
        {
            
            await Task.Delay(0); // 模拟异步操作
        }

        public async ValueTask DisposeAsync()
        {
            _cts.Cancel();
            await (_executionTask ?? Task.CompletedTask);
            _timer.Dispose();
            _semaphore.Dispose();
        }

        /// <summary>
        /// 获得需要处理的id集合
        /// </summary>
        /// <returns></returns>
        protected virtual List<long> GetProcessIds()
        {
            return new List<long>();
        }

        /// <summary>
        /// 处理执行
        /// </summary>
        protected async virtual Task Process()
        {
            eDate = DateTime.Now.Date.AddSeconds(-1);
            sDate = await GetLastDate();
            

            await Process(sDate, eDate);
        }

        protected async virtual Task Process(DateTime sdate, DateTime edate)
        {
            eDate = edate;
            BaseParm parm = BuildParm(sdate, edate);

            try
            {
                await DownLoadData(parm);

                //await SyncToU9();
            }
            catch (Exception ex)
            {

                LogUtil.Instance.Error(ex);
                LogUtil.Instance.Error(ex.StackTrace);
            }
        }

        protected virtual async Task DownLoadData(BaseParm parm)
        {
            await DeleteDirtyData();
        }

        protected virtual async Task SyncToU9()
        {
            await Task.CompletedTask;
        }
       
        protected virtual async Task<DateTime> GetLastDate()
        {
            string sql = $"select lastdate from dz_hd_sync_setting where doctype = '{docType}'";

            DateTime dt = await sqlUtils.ExecuteScalar<DateTime>(sql);

            return dt;
        }

        protected async Task SetLastDate()
        {
            string sql = $"update dz_hd_sync_setting set lastdate = '{eDate}' where doctype = '{docType}'";

            await sqlUtils.ExecuteNonQuery(sql);
        }

        protected virtual BaseParm BuildParm(DateTime sdate,DateTime edate)
        {
            return null;
        }

        public async Task PreProcessTest(DateTime sdate,DateTime edate)
        {
            await Process(sdate,edate);
        }

        /// <summary>
        /// 更新下载日志
        /// </summary>
        /// <param name="key"></param>
        
        /// <param name="flag">1：成功 -1 失败</param>
        /// <param name="error"></param>
        /// <returns></returns>
        protected async Task UpdateSyncLog(string key,int flag,string error="")
        {
            string sql = $"update dz_hd_jkysynclog set edate = getdate(),flag = {flag}, error = '{error}' where id = '{key}'";

            await sqlUtils.ExecuteNonQuery(sql);
        }


        
        protected async Task UpdateSyncLog(U9CResult result,string extWhere = "")
        {
            if (result.IsSuccess || result.Id > 0)
            {
                await UpdateDataState(2,extWhere);
            }
            await AddSyncDetailLog(result);
            
        }

        protected async Task AddSyncDetailLog(U9CResult result)
        {
            string sql = string.Empty;

            if (result.IsSuccess)
            {
                //全部成功
                sql = $@"insert into dz_hd_jkysynclog_detail(id,doctype,docno,docid,flag) 
                    values('{processId}','{docType}','{result.DocNo}',{result.Id},1)";
            }
            else
            {
                if(result.Id > 0)
                {
                    //部分成功
                    sql = $@"insert into dz_hd_jkysynclog_detail(id,doctype,docno,docid,flag) 
                    values('{processId}','{docType}','{result.DocNo}',{result.Id},2)";
                }
                else
                    {
                    sql = $@"insert into dz_hd_jkysynclog_detail(id,doctype,flag,msg) 
                    values('{processId}','{docType}',-1,'{result.Message}')";
                }
            }

                await sqlUtils.ExecuteNonQuery(sql);

            sql = $"exec usp_dz_updatesynclog '{processId}','{result.Message}'";

            await sqlUtils.ExecuteNonQuery(sql);
        }

        /// <summary>
        /// 新增下载日志
        /// </summary>
        /// <param name="key"></param>
        /// <param name="docType"></param>
        /// <returns></returns>
        protected async Task InsertSyncLog(string key, string docType)
        {
            string sql = @$"insert into dz_hd_jkysynclog(id,doctype,sdate) values('{key}','{docType}',getdate())";

            await sqlUtils.ExecuteNonQuery(sql);
        }

        /// <summary>
        /// 删除脏数据，下载数据前调用，防止重复下载（上次下载过程中异常退出，造成中间表内有脏数据）
        /// </summary>
        /// <returns></returns>
        protected async Task DeleteDirtyData()
        {
            string sql = @$"delete from {table} where xtype = 0";

            await sqlUtils.ExecuteNonQuery(sql);
        }

        /// <summary>
        /// 数据下载完成，生成U9单据后跟新数据表状态
        /// </summary>
        /// <param name="table">表名</param>
        /// <param name="type">状态 1：处理中 2：处理完成</param>
        /// <returns></returns>
        protected async Task UpdateDataState(int type,string extWhere="")
        {
            string sql = @$"update {table} set xtype = {type} where xtype = {type} - 1 {extWhere}";

            await sqlUtils.ExecuteNonQuery(sql);
        }
       
    }
}
